<script lang="ts">
type Item = { text: string; value: unknown };

type OptionItem = {
  key: string;
  type?: 'select' | 'date'; // select=>选择项 date=>日期项
  title: string;
  items?: Item[];
  value?: unknown;
};

// 克隆
function clone(value: unknown) {
  if (typeof value === 'object') {
    return JSON.parse(JSON.stringify(value));
  }
  return value;
}
</script>

<script lang="ts" setup>
import { ref, watch } from 'vue';

let initial: Record<string, unknown> = {}; // 初始值

let cache: Record<string, unknown> = {}; // 缓存区

const props = defineProps<{ title: string; data: OptionItem[] }>();

const emit = defineEmits<{
  (e: 'confirm', value: Record<string, unknown>): void;
}>();

const key = ref(0);

const show = ref(false); // 显示

const options = ref<OptionItem[]>([]); // 选项集合

const result = ref<Record<string, unknown>>(); // 结果

watch(
  () => props.data,
  () => {
    // 更新选择，并初始化缓存
    options.value = clone(props.data ?? []);
    initial = options.value.reduce((acc: Record<string, unknown>, item) => {
      acc[item.key] = clone(item.value);
      return acc;
    }, {});
  },
  { deep: true, immediate: true }
);

watch(
  () => show.value,
  (value) => {
    if (value) {
      // 刷缓存
      for (let i = 0, item; (item = options.value[i++]); ) {
        if (Object.keys(cache).length === 0) {
          item.value = clone(initial[item.key]);
        } else {
          item.value = clone(cache[item.key]);
        }
      }
      key.value += 1;
    }
  }
);

watch(
  () => options.value,
  (value) => {
    result.value = value.reduce((acc: Record<string, unknown>, item) => {
      acc[item.key] = item.value;
      return acc;
    }, {});
  },
  { deep: true }
);

/**
 * 显示
 */
const handleShow = (value = true) => {
  show.value = value;
};

/**
 * 选中
 */
const handleSelect = (index: number, value?: unknown) => {
  const item = options.value[index];

  switch (item.type) {
    case 'select':
      const _value = item.value;
      if (_value === '') {
        options.value[index].value = value;
      }
      if (_value !== '' && _value === value) {
        options.value[index].value = '';
      }
      if (_value !== '' && _value !== value) {
        options.value[index].value = value;
      }
      break;
    case 'date':
      options.value[index].value = value;
      break;
  }
};

/**
 * 删除
 */
const handleDelete = (index: number) => {
  options.value[index].value = [];
  key.value += 1;
};

/**
 * 重置
 */
const handleReset = () => {
  for (let i = 0, item; (item = options.value[i]); i++) {
    item.value = clone(initial[item.key]);
  }
  key.value += 1;
};

/**
 * 确认
 */
const handleConfirm = () => {
  show.value = false;
  cache = clone(result.value);
  emit('confirm', clone(result.value));
};

/**
 * 激活
 */
const isActive = (index: number, value: unknown) => {
  return options.value[index].value === value;
};

defineExpose({ handleShow });
</script>

<template>
  <van-popup class="filter-popup" v-model:show="show" round position="bottom">
    <div class="header">
      <div class="header__title">{{ props.title }}</div>
    </div>

    <div class="content">
      <div
        class="content__block"
        v-for="({ title, items, value, type }, oIndex) in options"
        :key="oIndex"
      >
        <template v-if="type === 'select'">
          <div class="content__title">{{ title }}</div>

          <div class="content__wrapper--select">
            <div
              class="content__value"
              v-for="(item, index) in items"
              :key="index"
              :class="{
                'content__status--active': isActive(oIndex, item.value),
              }"
              @click="() => handleSelect(oIndex, item.value)"
            >
              {{ item.text }}
            </div>
          </div>
        </template>

        <template v-if="type === 'date'">
          <div class="content__title">
            {{ title }}

            <van-icon name="delete-o" @click="() => handleDelete(oIndex)" />
          </div>

          <div class="content__wrapper--date" :key="key">
            <date-picker
              :data="value"
              @change="(event: string[]) => handleSelect(oIndex, event)"
            ></date-picker>
          </div>
        </template>
      </div>
    </div>

    <div class="footer">
      <div
        class="footer__button footer__button--reset"
        @click="() => handleReset()"
      >
        重置
      </div>

      <div
        class="footer__button footer__button--confirm"
        @click="() => handleConfirm()"
      >
        确认
      </div>
    </div>
  </van-popup>
</template>

<style lang="scss" scoped>
.header {
  position: relative;
  line-height: 48px;
  text-align: center;

  &__title {
    font-weight: 600;
    font-size: 14px;
    color: #333333;
  }
}

.content {
  width: 100%;
  max-height: 600px;
  overflow-y: auto;
  padding: 0 16px;

  &__block {
    margin-bottom: 16px;
  }

  &__title {
    display: flex;
    justify-content: space-between;
    align-items: center;

    margin-bottom: 12px;
    font-weight: 500;
    font-size: 14px;
    color: #333333;
  }

  &__wrapper {
    &--select {
      display: flex;
      flex-wrap: wrap;
      row-gap: 10px;
      column-gap: 8px;

      overflow-y: auto;
      max-height: 200px;
    }
  }

  &__wrapper--select &__value {
    display: flex;
    align-items: center;
    padding: 0 16px;
    height: 28px;
    border-radius: 17px;
    border: 1px solid #ebebeb;
    text-align: center;
    font-weight: 400;
    font-size: 12px;
    color: #666666;
  }

  &__wrapper--date &__value {
    display: flex;
    align-items: center;

    padding: 0 20px;
    height: 42px;
    background: #f4f4f4;
    border-radius: 22px 22px 22px 22px;

    color: #666666;
  }

  &__status {
    &--active {
      background: #7951f8;
      color: #ffffff !important;
    }

    &--default {
      color: #999999 !important;
    }
  }
}

.footer {
  display: flex;
  justify-content: space-between;
  padding: 0 16px 30px;

  &__button {
    flex: 1;
    display: flex;
    justify-content: center;
    align-items: center;

    height: 44px;
    border-radius: 22px;
    font-size: 16px;

    &--reset {
      border: 1px solid #7951f8;
      color: #7951f8;
    }

    &--confirm {
      background: linear-gradient(90deg, #984bff 0%, #415ceb 100%);
      color: #ffffff;
    }
  }

  &__button + &__button {
    margin-left: 15px;
  }
}
</style>
